<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>问卷测评演示v4</title>
    <!-- 引入TailwindCSS CDN -->
    <link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
    <!-- 引入阿里云OSS SDK -->
    <script src="https://gosspublic.alicdn.com/aliyun-oss-sdk-6.22.0.min.js"></script>
    <style>
        /* 自定义样式 */
        body {
            font-family: 'PingFang SC', 'Helvetica Neue', Arial, sans-serif;
            background-color: #f5f7fa;
        }

        .camera-container {
            position: fixed;
            top: 20px;
            right: 20px;
            z-index: 1000;
            border-radius: 8px;
            overflow: hidden;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
            transition: all 0.3s ease;
            width: 256px;
            height: 192px;
            cursor: move; /* 添加移动光标样式 */
        }

        .camera-container.hidden {
            display: none;
        }

        .iframe-container {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            z-index: 900;
            display: none;
        }

        .iframe-container.active {
            display: block;
        }

        .btn-primary {
            background: linear-gradient(135deg, #4f46e5, #6366f1);
            transition: all 0.3s ease;
        }

        .btn-primary:hover {
            background: linear-gradient(135deg, #4338ca, #4f46e5);
            transform: translateY(-2px);
            box-shadow: 0 4px 12px rgba(79, 70, 229, 0.3);
        }

        .camera-placeholder {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            display: flex;
            align-items: center;
            justify-content: center;
            background-color: #e5e7eb;
            color: #6b7280;
        }

        .close-btn {
            position: absolute;
            top: 5px;
            right: 5px;
            background-color: rgba(0, 0, 0, 0.5);
            color: white;
            border-radius: 50%;
            width: 24px;
            height: 24px;
            display: flex;
            align-items: center;
            justify-content: center;
            cursor: pointer;
            z-index: 1001;
        }

        #cameraView {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            object-fit: cover;
        }

        .status-indicator {
            position: absolute;
            bottom: 5px;
            left: 5px;
            background-color: rgba(0, 0, 0, 0.5);
            color: white;
            border-radius: 4px;
            padding: 2px 6px;
            font-size: 12px;
            z-index: 1001;
        }

        .record-indicator {
            position: absolute;
            top: 5px;
            left: 5px;
            width: 12px;
            height: 12px;
            border-radius: 50%;
            background-color: #ef4444;
            z-index: 1001;
            animation: blink 1s infinite;
        }

        @keyframes blink {
            0% { opacity: 1; }
            50% { opacity: 0.3; }
            100% { opacity: 1; }
        }

        .record-indicator.hidden {
            display: none;
        }
    </style>
</head>
<body class="min-h-screen flex flex-col items-center justify-center p-4">
    <div class="max-w-md w-full bg-white rounded-xl shadow-lg p-8 mb-8">
        <h1 class="text-3xl font-bold text-center text-gray-800 mb-6">问卷测评系统</h1>
        <p class="text-gray-600 mb-8 text-center">欢迎参与我们的问卷测评，点击下方按钮开始测评过程。</p>

        <div class="flex justify-center">
            <button id="startBtn" class="btn-primary text-white font-medium py-3 px-8 rounded-lg focus:outline-none">
                开始问卷测评
            </button>
        </div>
    </div>

    <!-- 摄像头容器 -->
    <div id="cameraContainer" class="camera-container hidden">
        <div class="close-btn" id="closeCamera">×</div>
        <div id="cameraPlaceholder" class="camera-placeholder">
            <span>等待权限...</span>
        </div>
        <video id="cameraView" autoplay playsinline class="hidden"></video>
        <div id="recordIndicator" class="record-indicator hidden"></div>
        <div id="statusIndicator" class="status-indicator hidden">准备中...</div>
    </div>

    <!-- iframe容器 -->
    <div id="iframeContainer" class="iframe-container">
        <iframe id="questionnaireFrame" src="" frameborder="0" class="w-full h-full"></iframe>
    </div>

    <script>
        // 获取DOM元素
        const startBtn = document.getElementById('startBtn');
        const cameraContainer = document.getElementById('cameraContainer');
        const cameraPlaceholder = document.getElementById('cameraPlaceholder');
        const cameraView = document.getElementById('cameraView');
        const iframeContainer = document.getElementById('iframeContainer');
        const questionnaireFrame = document.getElementById('questionnaireFrame');
        const closeCamera = document.getElementById('closeCamera');
        const statusIndicator = document.getElementById('statusIndicator');
        const recordIndicator = document.getElementById('recordIndicator');

        // 问卷URL（示例URL，实际使用时替换）
        const questionnaireUrl = 'https://psytest.ttmm.vip/storage/extracted-questionnaire/20250312093158_PX1XLyMKXO/index.html';

        // 阿里云OSS配置
        const ossConfig = {
            region: 'oss-cn-shanghai', // 地域
            bucket: 'psytest-001', // 存储桶名称
            videoInterval: 10000, // 视频录制间隔，单位毫秒
            videoDuration: 5000, // 每段视频的录制时长，单位毫秒
            directory: 'video-captures/', // 存储目录
            useVideo: true, // 是否使用视频录制（true）或图片拍照（false）
            fallbackToPhoto: true // 如果视频录制失败，是否回退到拍照模式
        };

        // 实现拖动功能
        let isDragging = false;
        let offsetX, offsetY;

        // 鼠标按下事件
        cameraContainer.addEventListener('mousedown', (e) => {
            // 如果点击的是关闭按钮，不启动拖动
            if (e.target === closeCamera) {
                return;
            }

            isDragging = true;

            // 计算鼠标在容器内的相对位置
            const rect = cameraContainer.getBoundingClientRect();
            offsetX = e.clientX - rect.left;
            offsetY = e.clientY - rect.top;

            // 防止拖动时选中文本
            e.preventDefault();
        });

        // 鼠标移动事件
        document.addEventListener('mousemove', (e) => {
            if (!isDragging) return;

            // 计算新位置
            const newLeft = e.clientX - offsetX;
            const newTop = e.clientY - offsetY;

            // 确保不超出屏幕边界
            const maxX = window.innerWidth - cameraContainer.offsetWidth;
            const maxY = window.innerHeight - cameraContainer.offsetHeight;

            // 设置新位置
            cameraContainer.style.left = `${Math.max(0, Math.min(maxX, newLeft))}px`;
            cameraContainer.style.top = `${Math.max(0, Math.min(maxY, newTop))}px`;
            cameraContainer.style.right = 'auto'; // 取消右侧定位
        });

        // 鼠标松开事件
        document.addEventListener('mouseup', () => {
            isDragging = false;
        });

        // 触摸设备支持
        cameraContainer.addEventListener('touchstart', (e) => {
            // 如果点击的是关闭按钮，不启动拖动
            if (e.target === closeCamera) {
                return;
            }

            isDragging = true;

            const touch = e.touches[0];
            const rect = cameraContainer.getBoundingClientRect();
            offsetX = touch.clientX - rect.left;
            offsetY = touch.clientY - rect.top;

            e.preventDefault();
        });

        document.addEventListener('touchmove', (e) => {
            if (!isDragging) return;

            const touch = e.touches[0];
            const newLeft = touch.clientX - offsetX;
            const newTop = touch.clientY - offsetY;

            const maxX = window.innerWidth - cameraContainer.offsetWidth;
            const maxY = window.innerHeight - cameraContainer.offsetHeight;

            cameraContainer.style.left = `${Math.max(0, Math.min(maxX, newLeft))}px`;
            cameraContainer.style.top = `${Math.max(0, Math.min(maxY, newTop))}px`;
            cameraContainer.style.right = 'auto';

            e.preventDefault();
        });

        document.addEventListener('touchend', () => {
            isDragging = false;
        });

        // 阿里云OSS客户端
        let ossClient = null;
        let captureInterval = null;
        let sessionId = null;
        let mediaRecorder = null;
        let recordedChunks = [];
        let isRecording = false;

        // 获取STS临时凭证（实际应用中需要从服务器获取）
        async function getSTSToken() {
            try {
                // 实际应用中，这里应该是向您的服务器请求STS临时凭证
                // 以下是示例代码，实际使用时需要替换为真实的API调用
                const response = await fetch('https://school-dy-api.psytest.ttmm.vip/api/home/oss/sts-token');
                console.log("response status:", response.status);

                if (!response.ok) {
                    throw new Error('获取STS凭证失败');
                }

                const data = await response.json();
                console.log("STS数据:", data);

                return {
                    accessKeyId: data.data.AccessKeyId,
                    accessKeySecret: data.data.AccessKeySecret,
                    stsToken: data.data.SecurityToken,
                    expiration: data.data.Expiration,
                    bucket: data.data.Bucket,
                    region: data.data.Region
                };
            } catch (error) {
                console.error('获取STS凭证出错:', error);
                // 为了演示，这里返回一个模拟的错误对象
                return { error: '获取STS凭证失败，请确保服务器端已正确配置' };
            }
        }

        // 初始化OSS客户端
        async function initOSSClient() {
            try {
                // 获取STS临时凭证
                const stsToken = await getSTSToken();
                console.log("stsToken", stsToken)
                if (stsToken.error) {
                    updateStatus(`错误: ${stsToken.error}`);
                    return false;
                }


                // 初始化OSS客户端
                ossClient = new OSS({
                    region: ossConfig.region,
                    accessKeyId: stsToken.accessKeyId,
                    accessKeySecret: stsToken.accessKeySecret,
                    stsToken: stsToken.stsToken,
                    bucket: stsToken.bucket,
                    secure: true // 使用HTTPS
                });

                // 生成唯一的会话ID
                sessionId = generateSessionId();
                updateStatus('OSS连接成功');
                return true;
            } catch (error) {
                console.error('初始化OSS客户端失败:', error);
                updateStatus('OSS连接失败');
                return false;
            }
        }

        // 生成唯一的会话ID
        function generateSessionId() {
            const timestamp = new Date().getTime();
            const random = Math.floor(Math.random() * 10000);
            return `session_${timestamp}_${random}`;
        }

        // 检查浏览器是否支持视频录制
        function checkVideoRecordingSupport(stream) {
            try {
                const supportedMimeTypes = [
                    'video/webm;codecs=vp9,opus',
                    'video/webm;codecs=vp8,opus',
                    'video/webm;codecs=h264,opus',
                    'video/mp4;codecs=h264,aac',
                    'video/webm',
                    'video/mp4'
                ];

                // 查找浏览器支持的MIME类型
                const mimeType = supportedMimeTypes.find(type => MediaRecorder.isTypeSupported(type));

                if (!mimeType) {
                    throw new Error('浏览器不支持任何视频录制格式');
                }

                // 尝试创建MediaRecorder实例
                const testRecorder = new MediaRecorder(stream, { mimeType });
                return { supported: true, mimeType };
            } catch (error) {
                console.error('视频录制不受支持:', error);
                return { supported: false, error: error.message };
            }
        }

        // 开始录制视频
        function startVideoRecording(stream, mimeType) {
            try {
                // 创建MediaRecorder实例
                mediaRecorder = new MediaRecorder(stream, { mimeType });
                recordedChunks = [];

                // 数据可用时的处理
                mediaRecorder.ondataavailable = (event) => {
                    if (event.data.size > 0) {
                        recordedChunks.push(event.data);
                    }
                };

                // 录制停止时的处理
                mediaRecorder.onstop = async () => {
                    if (recordedChunks.length > 0) {
                        await uploadVideoToOSS();
                    }

                    // 如果仍在捕获模式，则开始下一次录制
                    if (captureInterval) {
                        setTimeout(() => {
                            if (captureInterval) { // 再次检查，以防在延迟期间停止了捕获
                                startVideoRecording(stream, mimeType);
                            }
                        }, 500); // 短暂延迟，避免连续录制
                    }
                };

                // 录制错误处理
                mediaRecorder.onerror = (event) => {
                    console.error('视频录制错误:', event.error);
                    updateStatus(`录制错误: ${event.error}`);

                    // 如果配置了回退到拍照模式
                    if (ossConfig.fallbackToPhoto) {
                        ossConfig.useVideo = false;
                        updateStatus('已切换到拍照模式');
                        startCapturing();
                    }
                };

                // 开始录制
                mediaRecorder.start();
                isRecording = true;
                recordIndicator.classList.remove('hidden');
                updateStatus(`正在录制视频...`);

                // 设置录制时长
                setTimeout(() => {
                    if (mediaRecorder && mediaRecorder.state === 'recording') {
                        mediaRecorder.stop();
                        isRecording = false;
                        recordIndicator.classList.add('hidden');
                    }
                }, ossConfig.videoDuration);

            } catch (error) {
                console.error('开始视频录制失败:', error);
                updateStatus(`录制失败: ${error.message}`);

                // 如果配置了回退到拍照模式
                if (ossConfig.fallbackToPhoto) {
                    console.log('回退到拍照模式');
                    ossConfig.useVideo = false;
                    updateStatus('已切换到拍照模式');
                    startCapturing();
                }
            }
        }

        // 上传视频到OSS
        async function uploadVideoToOSS() {
            try {
                if (recordedChunks.length === 0) return;

                updateStatus('正在处理视频...');

                // 确定视频MIME类型
                let mimeType = 'video/webm';
                if (mediaRecorder && mediaRecorder.mimeType) {
                    mimeType = mediaRecorder.mimeType.split(';')[0]; // 获取基本MIME类型
                }

                // 创建Blob
                const videoBlob = new Blob(recordedChunks, { type: mimeType });

                // 生成文件扩展名
                let fileExt = 'webm';
                if (mimeType.includes('mp4')) {
                    fileExt = 'mp4';
                }

                // 生成文件名
                const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
                const fileName = `${ossConfig.directory}${sessionId}/${timestamp}.${fileExt}`;

                // 上传到OSS
                if (ossClient) {
                    updateStatus('正在上传视频...');
                    const result = await ossClient.put(fileName, videoBlob);

                    if (result && result.res && result.res.status === 200) {
                        updateStatus(`视频上传成功: ${timestamp}`);
                        // 清空已录制的数据
                        recordedChunks = [];
                    } else {
                        throw new Error('视频上传失败');
                    }
                } else {
                    throw new Error('OSS客户端未初始化');
                }
            } catch (error) {
                console.error('上传视频失败:', error);
                updateStatus(`视频上传失败: ${error.message}`);

                // 如果配置了回退到拍照模式
                if (ossConfig.fallbackToPhoto && ossConfig.useVideo) {
                    ossConfig.useVideo = false;
                    updateStatus('已切换到拍照模式');
                    startCapturing();
                }
            }
        }

        // 捕获并上传图像
        async function captureAndUpload() {
            if (!cameraView.srcObject) return;

            try {
                // 创建canvas元素
                const canvas = document.createElement('canvas');
                canvas.width = cameraView.videoWidth;
                canvas.height = cameraView.videoHeight;

                // 在canvas上绘制当前视频帧
                const ctx = canvas.getContext('2d');
                ctx.drawImage(cameraView, 0, 0, canvas.width, canvas.height);

                // 将canvas内容转换为Blob
                const blob = await new Promise(resolve => {
                    canvas.toBlob(resolve, 'image/jpeg', 0.85);
                });

                if (!blob) {
                    throw new Error('无法创建图像Blob');
                }

                // 生成文件名
                const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
                const fileName = `${ossConfig.directory}${sessionId}/${timestamp}.jpg`;

                // 上传到OSS
                if (ossClient) {
                    updateStatus('正在上传图片...');
                    const result = await ossClient.put(fileName, blob);

                    if (result && result.res && result.res.status === 200) {
                        updateStatus(`图片上传成功: ${timestamp}`);
                    } else {
                        throw new Error('上传失败');
                    }
                } else {
                    throw new Error('OSS客户端未初始化');
                }
            } catch (error) {
                console.error('捕获和上传图像失败:', error);
                updateStatus(`上传失败: ${error.message}`);
            }
        }

        // 更新状态指示器
        function updateStatus(message) {
            statusIndicator.textContent = message;
            statusIndicator.classList.remove('hidden');
        }

        // 开始捕获（视频或图像）
        function startCapturing() {
            if (ossConfig.useVideo) {
                // 检查视频录制支持
                const stream = cameraView.srcObject;
                const videoSupport = checkVideoRecordingSupport(stream);

                if (videoSupport.supported) {
                    // 开始视频录制
                    startVideoRecording(stream, videoSupport.mimeType);

                    // 设置定时器，定期开始新的录制
                    captureInterval = setInterval(() => {
                        // 如果当前正在录制，不做任何操作
                        if (isRecording) return;

                        startVideoRecording(stream, videoSupport.mimeType);
                    }, ossConfig.videoInterval);

                    updateStatus(`每${ossConfig.videoInterval / 1000}秒录制${ossConfig.videoDuration / 1000}秒视频`);
                } else {
                    console.warn('视频录制不受支持，切换到拍照模式:', videoSupport.error);
                    updateStatus(`视频录制不支持: ${videoSupport.error}`);

                    // 切换到拍照模式
                    ossConfig.useVideo = false;
                    startCapturing();
                }
            } else {
                // 拍照模式
                // 先执行一次捕获
                captureAndUpload();

                // 设置定时器，定期捕获
                captureInterval = setInterval(captureAndUpload, ossConfig.videoInterval);
                updateStatus(`每${ossConfig.videoInterval / 1000}秒自动拍照`);
            }
        }

        // 停止捕获
        function stopCapturing() {
            // 停止定时器
            if (captureInterval) {
                clearInterval(captureInterval);
                captureInterval = null;
            }

            // 停止视频录制
            if (mediaRecorder && mediaRecorder.state === 'recording') {
                mediaRecorder.stop();
                isRecording = false;
            }

            // 隐藏录制指示器
            recordIndicator.classList.add('hidden');
        }

        // 开始测评按钮点击事件
        startBtn.addEventListener('click', async () => {
            try {
                // 显示摄像头容器
                cameraContainer.classList.remove('hidden');

                // 请求摄像头权限
                const stream = await navigator.mediaDevices.getUserMedia({
                    video: {
                        width: 256,
                        height: 192,
                        facingMode: 'user'
                    },
                    audio: false
                });

                // 权限获取成功，显示摄像头画面
                cameraView.srcObject = stream;
                cameraPlaceholder.classList.add('hidden');
                cameraView.classList.remove('hidden');

                // 初始化OSS客户端并开始捕获
                const ossInitialized = await initOSSClient();
                if (ossInitialized) {
                    startCapturing();
                } else {
                    updateStatus('OSS初始化失败，无法上传');
                }

                // 打开问卷iframe
                questionnaireFrame.src = questionnaireUrl;
                iframeContainer.classList.add('active');

            } catch (err) {
                // 处理权限被拒绝的情况
                console.error('摄像头权限获取失败:', err);
                cameraPlaceholder.innerHTML = '<span class="text-red-500">摄像头权限被拒绝</span>';
            }
        });

        // 关闭摄像头按钮点击事件
        closeCamera.addEventListener('click', () => {
            // 停止捕获
            stopCapturing();

            // 停止摄像头流
            if (cameraView.srcObject) {
                const tracks = cameraView.srcObject.getTracks();
                tracks.forEach(track => track.stop());
            }

            // 隐藏摄像头容器
            cameraContainer.classList.add('hidden');

            // 重置摄像头视图
            cameraView.classList.add('hidden');
            cameraPlaceholder.classList.remove('hidden');
            cameraPlaceholder.innerHTML = '<span>等待摄像头权限...</span>';

            // 隐藏状态指示器
            statusIndicator.classList.add('hidden');
            recordIndicator.classList.add('hidden');

            // 关闭iframe
            iframeContainer.classList.remove('active');
            questionnaireFrame.src = '';
        });

        // 添加响应式调整
        window.addEventListener('resize', () => {
            // 根据窗口大小调整摄像头容器大小
            if (window.innerWidth < 640) { // 移动设备
                cameraContainer.style.width = '120px';
                cameraContainer.style.height = '90px';
            } else { // 桌面设备
                cameraContainer.style.width = '256px';
                cameraContainer.style.height = '192px';
            }
        });

        // 初始调整
        if (window.innerWidth < 640) {
            cameraContainer.style.width = '120px';
            cameraContainer.style.height = '90px';
        }
    </script>
</body>
</html>
